home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 6 / CU Amiga Magazine's Super CD-ROM 06 (1996)(EMAP Images)(GB)(Track 1 of 4)[!][issue 1997-01].iso / cucd / prog / gnu-c / src / gcc-2.7.0-amiga / objc / archive.c next >
C/C++ Source or Header  |  1995-06-15  |  39KB  |  1,617 lines

  1. /* GNU Objective C Runtime archiving
  2.    Copyright (C) 1993, 1995 Free Software Foundation, Inc.
  3.    Contributed by Kresten Krab Thorup
  4.  
  5. This file is part of GNU CC.
  6.  
  7. GNU CC is free software; you can redistribute it and/or modify it under the
  8. terms of the GNU General Public License as published by the Free Software
  9. Foundation; either version 2, or (at your option) any later version.
  10.  
  11. GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
  12. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  13. FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
  14. details.
  15.  
  16. You should have received a copy of the GNU General Public License along with
  17. GNU CC; see the file COPYING.  If not, write to the Free Software
  18. Foundation, 59 Temple Place - Suite 330,
  19. Boston, MA 02111-1307, USA.  */
  20.  
  21. /* As a special exception, if you link this library with files compiled with
  22.    GCC to produce an executable, this does not cause the resulting executable
  23.    to be covered by the GNU General Public License. This exception does not
  24.    however invalidate any other reasons why the executable file might be
  25.    covered by the GNU General Public License.  */
  26.  
  27. #include "runtime.h"
  28. #include "typedstream.h"
  29. #include "encoding.h"
  30.  
  31. extern int fflush(FILE*);
  32.  
  33. #define ROUND(V, A) \
  34.   ({ typeof(V) __v=(V); typeof(A) __a=(A);  \
  35.      __a*((__v+__a-1)/__a); })
  36.  
  37. #define PTR2LONG(P) (((char*)(P))-(char*)0)
  38. #define LONG2PTR(L) (((char*)0)+(L))
  39.  
  40. #define __objc_fatal(format, args...) \
  41.  { fprintf(stderr, "archiving: "); \
  42.    fprintf(stderr, format, ## args); \
  43.    fprintf(stderr, "\n"); abort(); }
  44.  
  45. /* Declare some functions... */
  46.  
  47. static int
  48. objc_read_class (struct objc_typed_stream* stream, Class* class);
  49.  
  50. int objc_sizeof_type(const char* type);
  51.  
  52. static int
  53. objc_write_use_common (struct objc_typed_stream* stream, unsigned long key);
  54.  
  55. static int
  56. objc_write_register_common (struct objc_typed_stream* stream,
  57.                 unsigned long key);
  58.  
  59. static int 
  60. objc_write_class (struct objc_typed_stream* stream,
  61.              struct objc_class* class);
  62.  
  63. const char* objc_skip_type (const char* type);
  64.  
  65. static void __objc_finish_write_root_object(struct objc_typed_stream*);
  66. static void __objc_finish_read_root_object(struct objc_typed_stream*);
  67.  
  68. static __inline__ int
  69. __objc_code_unsigned_char (unsigned char* buf, unsigned char val)
  70. {
  71.   if ((val&_B_VALUE) == val)
  72.     {
  73.       buf[0] = val|_B_SINT;
  74.       return 1;
  75.     }
  76.   else
  77.     {
  78.       buf[0] = _B_NINT|0x01;
  79.       buf[1] = val;
  80.       return 2;
  81.     }
  82. }
  83.  
  84. int
  85. objc_write_unsigned_char (struct objc_typed_stream* stream,
  86.               unsigned char value)
  87. {
  88.   unsigned char buf[sizeof (unsigned char)+1];
  89.   int len = __objc_code_unsigned_char (buf, value);
  90.   return (*stream->write)(stream->physical, buf, len);
  91. }
  92.  
  93. static __inline__ int
  94. __objc_code_char (unsigned char* buf, char val)
  95. {
  96.   if (val >= 0)
  97.     return __objc_code_unsigned_char (buf, val);
  98.   else
  99.     {
  100.       buf[0] = _B_NINT|_B_SIGN|0x01;
  101.       buf[1] = -val;
  102.       return 2;
  103.     }
  104. }
  105.  
  106. int
  107. objc_write_char (struct objc_typed_stream* stream, char value)
  108. {
  109.   unsigned char buf[sizeof (char)+1];
  110.   int len = __objc_code_char (buf, value);
  111.   return (*stream->write)(stream->physical, buf, len);
  112. }
  113.  
  114. static __inline__ int
  115. __objc_code_unsigned_short (unsigned char* buf, unsigned short val)
  116. {
  117.   if ((val&_B_VALUE) == val)
  118.     {
  119.       buf[0] = val|_B_SINT;
  120.       return 1;
  121.     }
  122.   else 
  123.     {
  124.       int c, b;
  125.  
  126.       buf[0] = _B_NINT;
  127.  
  128.       for (c= sizeof(short); c != 0; c -= 1)
  129.     if (((val>>(8*(c-1)))%0x100) != 0)
  130.       break;
  131.  
  132.       buf[0] |= c;
  133.  
  134.       for (b = 1; c != 0; c--, b++)
  135.     {
  136.       buf[b] = (val >> (8*(c-1)))%0x100;
  137.     }
  138.  
  139.       return b;
  140.     }
  141. }
  142.  
  143. int
  144. objc_write_unsigned_short (struct objc_typed_stream* stream, unsigned short value)
  145. {
  146.   unsigned char buf[sizeof (unsigned short)+1];
  147.   int len = __objc_code_unsigned_short (buf, value);
  148.   return (*stream->write)(stream->physical, buf, len);
  149. }
  150.       
  151. static __inline__ int
  152. __objc_code_short (unsigned char* buf, short val)
  153. {
  154.   int sign = (val < 0);
  155.   int size = __objc_code_unsigned_short (buf, sign ? -val : val);
  156.   if (sign)
  157.     buf[0] |= _B_SIGN;
  158.   return size;
  159. }
  160.  
  161. int
  162. objc_write_short (struct objc_typed_stream* stream, short value)
  163. {
  164.   unsigned char buf[sizeof (short)+1];
  165.   int len = __objc_code_short (buf, value);
  166.   return (*stream->write)(stream->physical, buf, len);
  167. }
  168.       
  169.  
  170. static __inline__ int
  171. __objc_code_unsigned_int (unsigned char* buf, unsigned int val)
  172. {
  173.   if ((val&_B_VALUE) == val)
  174.     {
  175.       buf[0] = val|_B_SINT;
  176.       return 1;
  177.     }
  178.   else 
  179.     {
  180.       int c, b;
  181.  
  182.       buf[0] = _B_NINT;
  183.  
  184.       for (c= sizeof(int); c != 0; c -= 1)
  185.     if (((val>>(8*(c-1)))%0x100) != 0)
  186.       break;
  187.  
  188.       buf[0] |= c;
  189.  
  190.       for (b = 1; c != 0; c--, b++)
  191.     {
  192.       buf[b] = (val >> (8*(c-1)))%0x100;
  193.     }
  194.  
  195.       return b;
  196.     }
  197. }
  198.  
  199. int
  200. objc_write_unsigned_int (struct objc_typed_stream* stream, unsigned int value)
  201. {
  202.   unsigned char buf[sizeof(unsigned int)+1];
  203.   int len = __objc_code_unsigned_int (buf, value);
  204.   return (*stream->write)(stream->physical, buf, len);
  205. }
  206.  
  207. static __inline__ int
  208. __objc_code_int (unsigned char* buf, int val)
  209. {
  210.   int sign = (val < 0);
  211.   int size = __objc_code_unsigned_int (buf, sign ? -val : val);
  212.   if (sign)
  213.     buf[0] |= _B_SIGN;
  214.   return size;
  215. }
  216.  
  217. int
  218. objc_write_int (struct objc_typed_stream* stream, int value)
  219. {
  220.   unsigned char buf[sizeof(int)+1];
  221.   int len = __objc_code_int (buf, value);
  222.   return (*stream->write)(stream->physical, buf, len);
  223. }
  224.  
  225. static __inline__ int
  226. __objc_code_unsigned_long (unsigned char* buf, unsigned long val)
  227. {
  228.   if ((val&_B_VALUE) == val)
  229.     {
  230.       buf[0] = val|_B_SINT;
  231.       return 1;
  232.     }
  233.   else 
  234.     {
  235.       int c, b;
  236.  
  237.       buf[0] = _B_NINT;
  238.  
  239.       for (c= sizeof(long); c != 0; c -= 1)
  240.     if (((val>>(8*(c-1)))%0x100) != 0)
  241.       break;
  242.  
  243.       buf[0] |= c;
  244.  
  245.       for (b = 1; c != 0; c--, b++)
  246.     {
  247.       buf[b] = (val >> (8*(c-1)))%0x100;
  248.     }
  249.  
  250.       return b;
  251.     }
  252. }
  253.  
  254. int
  255. objc_write_unsigned_long (struct objc_typed_stream* stream, unsigned long value)
  256. {
  257.   unsigned char buf[sizeof(unsigned long)+1];
  258.   int len = __objc_code_unsigned_long (buf, value);
  259.   return (*stream->write)(stream->physical, buf, len);
  260. }
  261.  
  262. static __inline__ int
  263. __objc_code_long (unsigned char* buf, long val)
  264. {
  265.   int sign = (val < 0);
  266.   int size = __objc_code_unsigned_long (buf, sign ? -val : val);
  267.   if (sign)
  268.     buf[0] |= _B_SIGN;
  269.   return size;
  270. }
  271.  
  272. int
  273. objc_write_long (struct objc_typed_stream* stream, long value)
  274. {
  275.   unsigned char buf[sizeof(long)+1];
  276.   int len = __objc_code_long (buf, value);
  277.   return (*stream->write)(stream->physical, buf, len);
  278. }
  279.  
  280.  
  281. int
  282. objc_write_string (struct objc_typed_stream* stream,
  283.            const unsigned char* string, unsigned int nbytes)
  284. {
  285.   unsigned char buf[sizeof(unsigned int)+1];
  286.   int len = __objc_code_unsigned_int (buf, nbytes);
  287.   
  288.   if ((buf[0]&_B_CODE) == _B_SINT)
  289.     buf[0] = (buf[0]&_B_VALUE)|_B_SSTR;
  290.  
  291.   else /* _B_NINT */
  292.     buf[0] = (buf[0]&_B_VALUE)|_B_NSTR;
  293.  
  294.   if ((*stream->write)(stream->physical, buf, len) != 0)
  295.     return (*stream->write)(stream->physical, string, nbytes);
  296.   else
  297.     return 0;
  298. }
  299.  
  300. int
  301. objc_write_string_atomic (struct objc_typed_stream* stream,
  302.               unsigned char* string, unsigned int nbytes)
  303. {
  304.   unsigned long key;
  305.   if ((key = PTR2LONG(hash_value_for_key (stream->stream_table, string))))
  306.     return objc_write_use_common (stream, key);
  307.   else
  308.     {
  309.       int length;
  310.       hash_add (&stream->stream_table, LONG2PTR(key=PTR2LONG(string)), string);
  311.       if ((length = objc_write_register_common (stream, key)))
  312.     return objc_write_string (stream, string, nbytes);
  313.       return length;
  314.     }
  315. }
  316.  
  317. static int
  318. objc_write_register_common (struct objc_typed_stream* stream, unsigned long key)
  319. {
  320.   unsigned char buf[sizeof (unsigned long)+2];
  321.   int len = __objc_code_unsigned_long (buf+1, key);
  322.   if (len == 1)
  323.     {
  324.       buf[0] = _B_RCOMM|0x01;
  325.       buf[1] &= _B_VALUE;
  326.       return (*stream->write)(stream->physical, buf, len+1);
  327.     }
  328.   else
  329.     {
  330.       buf[1] = (buf[1]&_B_VALUE)|_B_RCOMM;
  331.       return (*stream->write)(stream->physical, buf+1, len);
  332.     }
  333. }
  334.  
  335. static int
  336. objc_write_use_common (struct objc_typed_stream* stream, unsigned long key)
  337. {
  338.   unsigned char buf[sizeof (unsigned long)+2];
  339.   int len = __objc_code_unsigned_long (buf+1, key);
  340.   if (len == 1)
  341.     {
  342.       buf[0] = _B_UCOMM|0x01;
  343.       buf[1] &= _B_VALUE;
  344.       return (*stream->write)(stream->physical, buf, 2);
  345.     }
  346.   else
  347.     {
  348.       buf[1] = (buf[1]&_B_VALUE)|_B_UCOMM;
  349.       return (*stream->write)(stream->physical, buf+1, len);
  350.     }
  351. }
  352.  
  353. static __inline__ int
  354. __objc_write_extension (struct objc_typed_stream* stream, unsigned char code)
  355. {
  356.   if (code <= _B_VALUE)
  357.     {
  358.       unsigned char buf = code|_B_EXT;
  359.       return (*stream->write)(stream->physical, &buf, 1);
  360.     }
  361.   else 
  362.     abort();
  363. }
  364.  
  365. __inline__ int
  366. __objc_write_object (struct objc_typed_stream* stream, id object)
  367. {
  368.   unsigned char buf = '\0';
  369.   SEL write_sel = sel_get_any_uid ("write:");
  370.   if (object)
  371.     {
  372.       __objc_write_extension (stream, _BX_OBJECT);
  373.       objc_write_class (stream, object->class_pointer);
  374.       (*objc_msg_lookup(object, write_sel))(object, write_sel, stream);
  375.       return (*stream->write)(stream->physical, &buf, 1);
  376.     }
  377.   else
  378.     return objc_write_use_common(stream, 0);
  379. }
  380.  
  381. int 
  382. objc_write_object_reference (struct objc_typed_stream* stream, id object)
  383. {
  384.   unsigned long key;
  385.   if ((key = PTR2LONG(hash_value_for_key (stream->object_table, object))))
  386.     return objc_write_use_common (stream, key);
  387.  
  388.   __objc_write_extension (stream, _BX_OBJREF);
  389.   return objc_write_unsigned_long (stream, PTR2LONG (object));
  390. }
  391.  
  392. int 
  393. objc_write_root_object (struct objc_typed_stream* stream, id object)
  394. {
  395.   int len;
  396.   if (stream->writing_root_p)
  397.     __objc_fatal ("objc_write_root_object called recursively")
  398.   else
  399.     {
  400.       stream->writing_root_p = 1;
  401.       __objc_write_extension (stream, _BX_OBJROOT);
  402.       if((len = objc_write_object (stream, object)))
  403.     __objc_finish_write_root_object(stream);
  404.       stream->writing_root_p = 0;
  405.     }
  406.   return len;
  407. }
  408.  
  409. int 
  410. objc_write_object (struct objc_typed_stream* stream, id object)
  411. {
  412.   unsigned long key;
  413.   if ((key = PTR2LONG(hash_value_for_key (stream->object_table, object))))
  414.     return objc_write_use_common (stream, key);
  415.  
  416.   else if (object == nil)
  417.     return objc_write_use_common(stream, 0);
  418.  
  419.   else
  420.     {
  421.       int length;
  422.       hash_add (&stream->object_table, LONG2PTR(key=PTR2LONG(object)), object);
  423.       if ((length = objc_write_register_common (stream, key)))
  424.     return __objc_write_object (stream, object);
  425.       return length;
  426.     }
  427. }
  428.  
  429. #ifdef __alpha__
  430. extern int atoi (const char*);
  431. extern size_t strlen(const char*);
  432. extern size_t strcpy(char*, const char*);
  433. #endif
  434.  
  435. __inline__ int
  436. __objc_write_class (struct objc_typed_stream* stream, struct objc_class* class)
  437. {
  438.   __objc_write_extension (stream, _BX_CLASS);
  439.   objc_write_string_atomic(stream, (char*)class->name,
  440.                strlen((char*)class->name));
  441.   return objc_write_unsigned_long (stream, class->version);
  442. }
  443.  
  444.  
  445. static int 
  446. objc_write_class (struct objc_typed_stream* stream,
  447.              struct objc_class* class)
  448. {
  449.   unsigned long key;
  450.   if ((key = PTR2LONG(hash_value_for_key (stream->stream_table, class))))
  451.     return objc_write_use_common (stream, key);
  452.   else
  453.     {
  454.       int length;
  455.       hash_add (&stream->stream_table, LONG2PTR(key=PTR2LONG(class)), class);
  456.       if ((length = objc_write_register_common (stream, key)))
  457.     return __objc_write_class (stream, class);
  458.       return length;
  459.     }
  460. }
  461.  
  462.  
  463. __inline__ int 
  464. __objc_write_selector (struct objc_typed_stream* stream, SEL selector)
  465. {
  466.   const char* sel_name;
  467.   __objc_write_extension (stream, _BX_SEL);
  468.   /* to handle NULL selectors */
  469.   if ((SEL)0 == selector)
  470.     return objc_write_string (stream, "", 0);
  471.   sel_name = sel_get_name (selector);
  472.   return objc_write_string (stream, sel_name, strlen ((char*)sel_name));
  473. }
  474.  
  475. int 
  476. objc_write_selector (struct objc_typed_stream* stream, SEL selector)
  477. {
  478.   const char* sel_name;
  479.   unsigned long key;
  480.  
  481.   /* to handle NULL selectors */
  482.   if ((SEL)0 == selector)
  483.     return __objc_write_selector (stream, selector);
  484.  
  485.   sel_name = sel_get_name (selector);
  486.   if ((key = PTR2LONG(hash_value_for_key (stream->stream_table, sel_name))))
  487.     return objc_write_use_common (stream, key);
  488.   else
  489.     {
  490.       int length;
  491.       hash_add (&stream->stream_table, LONG2PTR(key=PTR2LONG(sel_name)), (char*)sel_name);
  492.       if ((length = objc_write_register_common (stream, key)))
  493.     return __objc_write_selector (stream, selector);
  494.       return length;
  495.     }
  496. }
  497.  
  498.  
  499.  
  500. /*
  501. ** Read operations 
  502. */
  503.  
  504. __inline__ int
  505. objc_read_char (struct objc_typed_stream* stream, char* val)
  506. {
  507.   unsigned char buf;
  508.   int len;
  509.   len = (*stream->read)(stream->physical, &buf, 1);
  510.   if (len != 0)
  511.     {
  512.       if ((buf & _B_CODE) == _B_SINT)
  513.     (*val) = (buf & _B_VALUE);
  514.  
  515.       else if ((buf & _B_NUMBER) == 1)
  516.     {
  517.       len = (*stream->read)(stream->physical, val, 1);
  518.       if (buf&_B_SIGN)
  519.         (*val) = -1*(*val);
  520.     }
  521.  
  522.       else
  523.     __objc_fatal("expected 8bit signed int, got %dbit int",
  524.              (int)(buf&_B_NUMBER)*8);
  525.     }
  526.   return len;
  527. }
  528.  
  529.  
  530. __inline__ int
  531. objc_read_unsigned_char (struct objc_typed_stream* stream, unsigned char* val)
  532. {
  533.   unsigned char buf;
  534.   int len;
  535.   if ((len = (*stream->read)(stream->physical, &buf, 1)))
  536.     {
  537.       if ((buf & _B_CODE) == _B_SINT)
  538.     (*val) = (buf & _B_VALUE);
  539.  
  540.       else if ((buf & _B_NUMBER) == 1)
  541.     len = (*stream->read)(stream->physical, val, 1);
  542.  
  543.       else
  544.     __objc_fatal("expected 8bit unsigned int, got %dbit int",
  545.              (int)(buf&_B_NUMBER)*8);
  546.     }
  547.   return len;
  548. }
  549.  
  550. __inline__ int
  551. objc_read_short (struct objc_typed_stream* stream, short* value)
  552. {
  553.   unsigned char buf[sizeof(short)+1];
  554.   int len;
  555.   if ((len = (*stream->read)(stream->physical, buf, 1)))
  556.     {
  557.       if ((buf[0] & _B_CODE) == _B_SINT)
  558.     (*value) = (buf[0] & _B_VALUE);
  559.  
  560.       else
  561.     {
  562.       int pos = 1;
  563.       int nbytes = buf[0] & _B_NUMBER;
  564.       if (nbytes > sizeof (short))
  565.         __objc_fatal("expected short, got bigger (%dbits)", nbytes*8);
  566.       len = (*stream->read)(stream->physical, buf+1, nbytes);
  567.       (*value) = 0;
  568.       while (pos <= nbytes)
  569.         (*value) = ((*value)*0x100) + buf[pos++];
  570.       if (buf[0] & _B_SIGN)
  571.         (*value) = -(*value);
  572.     }
  573.     }
  574.   return len;
  575. }
  576.  
  577. __inline__ int
  578. objc_read_unsigned_short (struct objc_typed_stream* stream,
  579.               unsigned short* value)
  580. {
  581.   unsigned char buf[sizeof(unsigned short)+1];
  582.   int len;
  583.   if ((len = (*stream->read)(stream->physical, buf, 1)))
  584.     {
  585.       if ((buf[0] & _B_CODE) == _B_SINT)
  586.     (*value) = (buf[0] & _B_VALUE);
  587.  
  588.       else
  589.     {
  590.       int pos = 1;
  591.       int nbytes = buf[0] & _B_NUMBER;
  592.       if (nbytes > sizeof (short))
  593.         __objc_fatal("expected short, got int or bigger");
  594.       len = (*stream->read)(stream->physical, buf+1, nbytes);
  595.       (*value) = 0;
  596.       while (pos <= nbytes)
  597.         (*value) = ((*value)*0x100) + buf[pos++];
  598.     }
  599.     }
  600.   return len;
  601. }
  602.  
  603.  
  604. __inline__ int
  605. objc_read_int (struct objc_typed_stream* stream, int* value)
  606. {
  607.   unsigned char buf[sizeof(int)+1];
  608.   int len;
  609.   if ((len = (*stream->read)(stream->physical, buf, 1)))
  610.     {
  611.       if ((buf[0] & _B_CODE) == _B_SINT)
  612.     (*value) = (buf[0] & _B_VALUE);
  613.  
  614.       else
  615.     {
  616.       int pos = 1;
  617.       int nbytes = buf[0] & _B_NUMBER;
  618.       if (nbytes > sizeof (int))
  619.         __objc_fatal("expected int, got bigger");
  620.       len = (*stream->read)(stream->physical, buf+1, nbytes);
  621.       (*value) = 0;
  622.       while (pos <= nbytes)
  623.         (*value) = ((*value)*0x100) + buf[pos++];
  624.       if (buf[0] & _B_SIGN)
  625.         (*value) = -(*value);
  626.     }
  627.     }
  628.   return len;
  629. }
  630.  
  631. __inline__ int
  632. objc_read_long (struct objc_typed_stream* stream, long* value)
  633. {
  634.   unsigned char buf[sizeof(long)+1];
  635.   int len;
  636.   if ((len = (*stream->read)(stream->physical, buf, 1)))
  637.     {
  638.       if ((buf[0] & _B_CODE) == _B_SINT)
  639.     (*value) = (buf[0] & _B_VALUE);
  640.  
  641.       else
  642.     {
  643.       int pos = 1;
  644.       int nbytes = buf[0] & _B_NUMBER;
  645.       if (nbytes > sizeof (long))
  646.         __objc_fatal("expected long, got bigger");
  647.       len = (*stream->read)(stream->physical, buf+1, nbytes);
  648.       (*value) = 0;
  649.       while (pos <= nbytes)
  650.         (*value) = ((*value)*0x100) + buf[pos++];
  651.       if (buf[0] & _B_SIGN)
  652.         (*value) = -(*value);
  653.     }
  654.     }
  655.   return len;
  656. }
  657.  
  658. __inline__ int
  659. __objc_read_nbyte_uint (struct objc_typed_stream* stream,
  660.                unsigned int nbytes, unsigned int* val)
  661. {
  662.   int len, pos = 0;
  663.   unsigned char buf[sizeof(unsigned int)+1];
  664.  
  665.   if (nbytes > sizeof (int))
  666.     __objc_fatal("expected int, got bigger");
  667.  
  668.   len = (*stream->read)(stream->physical, buf, nbytes);
  669.   (*val) = 0;
  670.   while (pos < nbytes)
  671.     (*val) = ((*val)*0x100) + buf[pos++];
  672.   return len;
  673. }
  674.   
  675.  
  676. __inline__ int
  677. objc_read_unsigned_int (struct objc_typed_stream* stream,
  678.             unsigned int* value)
  679. {
  680.   unsigned char buf[sizeof(unsigned int)+1];
  681.   int len;
  682.   if ((len = (*stream->read)(stream->physical, buf, 1)))
  683.     {
  684.       if ((buf[0] & _B_CODE) == _B_SINT)
  685.     (*value) = (buf[0] & _B_VALUE);
  686.  
  687.       else
  688.     len = __objc_read_nbyte_uint (stream, (buf[0] & _B_VALUE), value);
  689.  
  690.     }
  691.   return len;
  692. }
  693.  
  694. int
  695. __objc_read_nbyte_ulong (struct objc_typed_stream* stream,
  696.                unsigned int nbytes, unsigned long* val)
  697. {
  698.   int len, pos = 0;
  699.   unsigned char buf[sizeof(unsigned long)+1];
  700.  
  701.   if (nbytes > sizeof (long))
  702.     __objc_fatal("expected long, got bigger");
  703.  
  704.   len = (*stream->read)(stream->physical, buf, nbytes);
  705.   (*val) = 0;
  706.   while (pos < nbytes)
  707.     (*val) = ((*val)*0x100) + buf[pos++];
  708.   return len;
  709. }
  710.   
  711.  
  712. __inline__ int
  713. objc_read_unsigned_long (struct objc_typed_stream* stream,
  714.             unsigned long* value)
  715. {
  716.   unsigned char buf[sizeof(unsigned long)+1];
  717.   int len;
  718.   if ((len = (*stream->read)(stream->physical, buf, 1)))
  719.     {
  720.       if ((buf[0] & _B_CODE) == _B_SINT)
  721.     (*value) = (buf[0] & _B_VALUE);
  722.  
  723.       else
  724.     len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), value);
  725.  
  726.     }
  727.   return len;
  728. }
  729.  
  730. __inline__ int
  731. objc_read_string (struct objc_typed_stream* stream,
  732.           char** string)
  733. {
  734.   unsigned char buf[sizeof(unsigned int)+1];
  735.   int len;
  736.   if ((len = (*stream->read)(stream->physical, buf, 1)))
  737.     {
  738.       unsigned long key = 0;
  739.  
  740.       if ((buf[0]&_B_CODE) == _B_RCOMM)    /* register following */
  741.     {
  742.       len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
  743.       len = (*stream->read)(stream->physical, buf, 1);
  744.     }
  745.  
  746.       switch (buf[0]&_B_CODE) {
  747.       case _B_SSTR:
  748.     {
  749.       int length = buf[0]&_B_VALUE;
  750.       (*string) = (char*)__objc_xmalloc(length+1);
  751.       if (key)
  752.         hash_add (&stream->stream_table, LONG2PTR(key), *string);
  753.       len = (*stream->read)(stream->physical, *string, length);
  754.       (*string)[length] = '\0';
  755.     }
  756.     break;
  757.  
  758.       case _B_UCOMM:
  759.     {
  760.       char *tmp;
  761.       len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
  762.       tmp = hash_value_for_key (stream->stream_table, LONG2PTR (key));
  763.       *string = __objc_xmalloc (strlen(tmp) + 1);
  764.       strcpy (*string, tmp);
  765.     }
  766.     break;
  767.  
  768.       case _B_NSTR:
  769.     {
  770.       unsigned int nbytes = buf[0]&_B_VALUE;
  771.       len = __objc_read_nbyte_uint(stream, nbytes, &nbytes);
  772.       if (len) {
  773.         (*string) = (char*)__objc_xmalloc(nbytes+1);
  774.         if (key)
  775.           hash_add (&stream->stream_table, LONG2PTR(key), *string);
  776.         len = (*stream->read)(stream->physical, *string, nbytes);
  777.         (*string)[nbytes] = '\0';
  778.       }
  779.     }
  780.     break;
  781.     
  782.       default:
  783.     __objc_fatal("expected string, got opcode %c\n", (buf[0]&_B_CODE));
  784.       }
  785.     }
  786.  
  787.   return len;
  788. }
  789.  
  790.  
  791. int
  792. objc_read_object (struct objc_typed_stream* stream, id* object)
  793. {
  794.   unsigned char buf[sizeof (unsigned int)];
  795.   int len;
  796.   if ((len = (*stream->read)(stream->physical, buf, 1)))
  797.     {
  798.       SEL read_sel = sel_get_any_uid ("read:");
  799.       unsigned long key = 0;
  800.  
  801.       if ((buf[0]&_B_CODE) == _B_RCOMM)    /* register common */
  802.     {
  803.       len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
  804.       len = (*stream->read)(stream->physical, buf, 1);
  805.     }
  806.  
  807.       if (buf[0] == (_B_EXT | _BX_OBJECT))
  808.     {
  809.       Class class;
  810.  
  811.       /* get class */
  812.       len = objc_read_class (stream, &class);
  813.  
  814.       /* create instance */
  815.       (*object) = class_create_instance(class);
  816.  
  817.       /* register? */
  818.       if (key)
  819.         hash_add (&stream->object_table, LONG2PTR(key), *object);
  820.  
  821.       /* send -read: */
  822.       if (__objc_responds_to (*object, read_sel))
  823.         (*get_imp(class, read_sel))(*object, read_sel, stream);
  824.  
  825.       /* check null-byte */
  826.       len = (*stream->read)(stream->physical, buf, 1);
  827.       if (buf[0] != '\0')
  828.         __objc_fatal("expected null-byte, got opcode %c", buf[0]);
  829.     }
  830.  
  831.       else if ((buf[0]&_B_CODE) == _B_UCOMM)
  832.     {
  833.       if (key)
  834.         __objc_fatal("cannot register use upcode...");
  835.       len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
  836.       (*object) = hash_value_for_key (stream->object_table, LONG2PTR(key));
  837.     }
  838.  
  839.       else if (buf[0] == (_B_EXT | _BX_OBJREF))    /* a forward reference */
  840.     {
  841.       struct objc_list* other;
  842.       len = objc_read_unsigned_long (stream, &key);
  843.       other = (struct objc_list*)hash_value_for_key (stream->object_refs, LONG2PTR(key));
  844.       hash_add (&stream->object_refs, LONG2PTR(key), (void*)list_cons(object, other));
  845.     }
  846.  
  847.       else if (buf[0] == (_B_EXT | _BX_OBJROOT)) /* a root object */
  848.     {
  849.       if (key)
  850.         __objc_fatal("cannot register root object...");
  851.       len = objc_read_object (stream, object);
  852.       __objc_finish_read_root_object (stream);
  853.     }
  854.  
  855.       else
  856.     __objc_fatal("expected object, got opcode %c", buf[0]);
  857.     }
  858.   return len;
  859. }
  860.  
  861. static int
  862. objc_read_class (struct objc_typed_stream* stream, Class* class)
  863. {
  864.   unsigned char buf[sizeof (unsigned int)];
  865.   int len;
  866.   if ((len = (*stream->read)(stream->physical, buf, 1)))
  867.     {
  868.       unsigned long key = 0;
  869.  
  870.       if ((buf[0]&_B_CODE) == _B_RCOMM)    /* register following */
  871.     {
  872.       len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
  873.       len = (*stream->read)(stream->physical, buf, 1);
  874.     }
  875.  
  876.       if (buf[0] == (_B_EXT | _BX_CLASS))
  877.     {
  878.       char* class_name;
  879.       unsigned long version;
  880.  
  881.       /* get class */
  882.       len = objc_read_string (stream, &class_name);
  883.       (*class) = objc_get_class(class_name);
  884.       free (class_name);
  885.  
  886.       /* register */
  887.       if (key)
  888.         hash_add (&stream->stream_table, LONG2PTR(key), *class);
  889.  
  890.       objc_read_unsigned_long(stream, &version);
  891.       hash_add (&stream->class_table, (*class)->name, (void*)version);
  892.     }
  893.  
  894.       else if ((buf[0]&_B_CODE) == _B_UCOMM)
  895.     {
  896.       if (key)
  897.         __objc_fatal("cannot register use upcode...");
  898.       len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
  899.       (*class) = hash_value_for_key (stream->stream_table, LONG2PTR(key));
  900.       if (!*class)
  901.         __objc_fatal("cannot find class for key %lu", key);
  902.     }
  903.  
  904.       else
  905.     __objc_fatal("expected class, got opcode %c", buf[0]);
  906.     }
  907.   return len;
  908. }
  909.  
  910. int
  911. objc_read_selector (struct objc_typed_stream* stream, SEL* selector)
  912. {
  913.   unsigned char buf[sizeof (unsigned int)];
  914.   int len;
  915.   if ((len = (*stream->read)(stream->physical, buf, 1)))
  916.     {
  917.       unsigned long key = 0;
  918.  
  919.       if ((buf[0]&_B_CODE) == _B_RCOMM)    /* register following */
  920.     {
  921.       len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
  922.       len = (*stream->read)(stream->physical, buf, 1);
  923.     }
  924.  
  925.       if (buf[0] == (_B_EXT|_BX_SEL)) /* selector! */
  926.     {
  927.       char* selector_name;
  928.  
  929.       /* get selector */
  930.       len = objc_read_string (stream, &selector_name);
  931.       /* To handle NULL selectors */
  932.       if (0 == strlen(selector_name))
  933.         {
  934.           (*selector) = (SEL)0;
  935.           return 0;
  936.         }
  937.       else 
  938.         (*selector) = sel_get_any_uid(selector_name);
  939.       free (selector_name);
  940.  
  941.       /* register */
  942.       if (key)
  943.         hash_add (&stream->stream_table, LONG2PTR(key), (void*)*selector);
  944.     }
  945.  
  946.       else if ((buf[0]&_B_CODE) == _B_UCOMM)
  947.     {
  948.       if (key)
  949.         __objc_fatal("cannot register use upcode...");
  950.       len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
  951.       (*selector) = hash_value_for_key (stream->stream_table, LONG2PTR(key));
  952.     }
  953.  
  954.       else
  955.     __objc_fatal("expected selector, got opcode %c", buf[0]);
  956.     }
  957.   return len;
  958. }
  959.  
  960. /*
  961. ** USER LEVEL FUNCTIONS
  962. */
  963.  
  964. /*
  965. ** Write one object, encoded in TYPE and pointed to by DATA to the
  966. ** typed stream STREAM.  
  967. */
  968.  
  969. int
  970. objc_write_type(TypedStream* stream, const char* type, const void* data)
  971. {
  972.   switch(*type) {
  973.   case _C_ID:
  974.     return objc_write_object (stream, *(id*)data);
  975.     break;
  976.  
  977.   case _C_CLASS:
  978.     return objc_write_class (stream, *(Class*)data);
  979.     break;
  980.  
  981.   case _C_SEL:
  982.     return objc_write_selector (stream, *(SEL*)data);
  983.     break;
  984.  
  985.   case _C_CHR:
  986.     return objc_write_char(stream, *(char*)data);
  987.     break;
  988.     
  989.   case _C_UCHR:
  990.     return objc_write_unsigned_char(stream, *(unsigned char*)data);
  991.     break;
  992.  
  993.   case _C_SHT:
  994.     return objc_write_short(stream, *(short*)data);
  995.     break;
  996.  
  997.   case _C_USHT:
  998.     return objc_write_unsigned_short(stream, *(unsigned short*)data);
  999.     break;
  1000.  
  1001.   case _C_INT:
  1002.     return objc_write_int(stream, *(int*)data);
  1003.     break;
  1004.  
  1005.   case _C_UINT:
  1006.     return objc_write_unsigned_int(stream, *(unsigned int*)data);
  1007.     break;
  1008.  
  1009.   case _C_LNG:
  1010.     return objc_write_long(stream, *(long*)data);
  1011.     break;
  1012.  
  1013.   case _C_ULNG:
  1014.     return objc_write_unsigned_long(stream, *(unsigned long*)data);
  1015.     break;
  1016.  
  1017.   case _C_CHARPTR:
  1018.     return objc_write_string (stream, *(char**)data, strlen(*(char**)data));
  1019.     break;
  1020.  
  1021.   case _C_ATOM:
  1022.     return objc_write_string_atomic (stream, *(char**)data, strlen(*(char**)data));
  1023.     break;
  1024.  
  1025.   case _C_ARY_B:
  1026.     {
  1027.       int len = atoi(type+1);
  1028.       while (isdigit(*++type));
  1029.       return objc_write_array (stream, type, len, data);
  1030.     }
  1031.     break; 
  1032.  
  1033.   case _C_STRUCT_B:
  1034.     {
  1035.       int acc_size = 0;
  1036.       int align;
  1037.       while (*type != _C_STRUCT_E && *type++ != '='); /* skip "<name>=" */
  1038.       while (*type != _C_STRUCT_E);
  1039.     {
  1040.       align = objc_alignof_type (type);       /* padd to alignment */
  1041.       acc_size += ROUND (acc_size, align);
  1042.       objc_write_type (stream, type, ((char*)data)+acc_size);
  1043.       acc_size += objc_sizeof_type (type);   /* add component size */
  1044.       type = objc_skip_typespec (type);     /* skip component */
  1045.     }
  1046.       return 1;
  1047.     }
  1048.  
  1049.   default:
  1050.     fprintf(stderr, "objc_write_type: cannot parse typespec: %s\n", type);
  1051.     abort();
  1052.   }
  1053. }
  1054.  
  1055. /*
  1056. ** Read one object, encoded in TYPE and pointed to by DATA to the
  1057. ** typed stream STREAM.  DATA specifies the address of the types to
  1058. ** read.  Expected type is checked against the type actually present
  1059. ** on the stream. 
  1060. */
  1061.  
  1062. int
  1063. objc_read_type(TypedStream* stream, const char* type, void* data)
  1064. {
  1065.   char c;
  1066.   switch(c = *type) {
  1067.   case _C_ID:
  1068.     return objc_read_object (stream, (id*)data);
  1069.     break;
  1070.  
  1071.   case _C_CLASS:
  1072.     return objc_read_class (stream, (Class*)data);
  1073.     break;
  1074.  
  1075.   case _C_SEL:
  1076.     return objc_read_selector (stream, (SEL*)data);
  1077.     break;
  1078.  
  1079.   case _C_CHR:
  1080.     return objc_read_char (stream, (char*)data);
  1081.     break;
  1082.     
  1083.   case _C_UCHR:
  1084.     return objc_read_unsigned_char (stream, (unsigned char*)data);
  1085.     break;
  1086.  
  1087.   case _C_SHT:
  1088.     return objc_read_short (stream, (short*)data);
  1089.     break;
  1090.  
  1091.   case _C_USHT:
  1092.     return objc_read_unsigned_short (stream, (unsigned short*)data);
  1093.     break;
  1094.  
  1095.   case _C_INT:
  1096.     return objc_read_int (stream, (int*)data);
  1097.     break;
  1098.  
  1099.   case _C_UINT:
  1100.     return objc_read_unsigned_int (stream, (unsigned int*)data);
  1101.     break;
  1102.  
  1103.   case _C_LNG:
  1104.     return objc_read_long (stream, (long*)data);
  1105.     break;
  1106.  
  1107.   case _C_ULNG:
  1108.     return objc_read_unsigned_long (stream, (unsigned long*)data);
  1109.     break;
  1110.  
  1111.   case _C_CHARPTR:
  1112.   case _C_ATOM:
  1113.     return objc_read_string (stream, (char**)data);
  1114.     break;
  1115.  
  1116.   case _C_ARY_B:
  1117.     {
  1118.       int len = atoi(type+1);
  1119.       while (isdigit(*++type));
  1120.       return objc_read_array (stream, type, len, data);
  1121.     }
  1122.     break; 
  1123.  
  1124.   case _C_STRUCT_B:
  1125.     {
  1126.       int acc_size = 0;
  1127.       int align;
  1128.       while (*type != _C_STRUCT_E && *type++ != '='); /* skip "<name>=" */
  1129.       while (*type != _C_STRUCT_E);
  1130.     {
  1131.       align = objc_alignof_type (type);       /* padd to alignment */
  1132.       acc_size += ROUND (acc_size, align);
  1133.       objc_read_type (stream, type, ((char*)data)+acc_size);
  1134.       acc_size += objc_sizeof_type (type);   /* add component size */
  1135.       type = objc_skip_typespec (type);     /* skip component */
  1136.     }
  1137.       return 1;
  1138.     }
  1139.  
  1140.   default:
  1141.     fprintf(stderr, "objc_read_type: cannot parse typespec: %s\n", type);
  1142.     abort();
  1143.   }
  1144. }
  1145.  
  1146. /*
  1147. ** Write the object specified by the template TYPE to STREAM.  Last
  1148. ** arguments specify addresses of values to be written.  It might 
  1149. ** seem surprising to specify values by address, but this is extremely
  1150. ** convenient for copy-paste with objc_read_types calls.  A more
  1151. ** down-to-the-earth cause for this passing of addresses is that values
  1152. ** of arbitrary size is not well supported in ANSI C for functions with
  1153. ** variable number of arguments.
  1154. */
  1155.  
  1156. int 
  1157. objc_write_types (TypedStream* stream, const char* type, ...)
  1158. {
  1159.   va_list args;
  1160.   const char *c;
  1161.   int res = 0;
  1162.  
  1163.   va_start(args, type);
  1164.  
  1165.   for (c = type; *c; c = objc_skip_typespec (c))
  1166.     {
  1167.       switch(*c) {
  1168.       case _C_ID:
  1169.     res = objc_write_object (stream, *va_arg (args, id*));
  1170.     break;
  1171.  
  1172.       case _C_CLASS:
  1173.     res = objc_write_class (stream, *va_arg(args, Class*));
  1174.     break;
  1175.  
  1176.       case _C_SEL:
  1177.     res = objc_write_selector (stream, *va_arg(args, SEL*));
  1178.     break;
  1179.     
  1180.       case _C_CHR:
  1181.     res = objc_write_char (stream, *va_arg (args, char*));
  1182.     break;
  1183.     
  1184.       case _C_UCHR:
  1185.     res = objc_write_unsigned_char (stream,
  1186.                     *va_arg (args, unsigned char*));
  1187.     break;
  1188.     
  1189.       case _C_SHT:
  1190.     res = objc_write_short (stream, *va_arg(args, short*));
  1191.     break;
  1192.  
  1193.       case _C_USHT:
  1194.     res = objc_write_unsigned_short (stream,
  1195.                      *va_arg(args, unsigned short*));
  1196.     break;
  1197.  
  1198.       case _C_INT:
  1199.     res = objc_write_int(stream, *va_arg(args, int*));
  1200.     break;
  1201.     
  1202.       case _C_UINT:
  1203.     res = objc_write_unsigned_int(stream, *va_arg(args, unsigned int*));
  1204.     break;
  1205.  
  1206.       case _C_LNG:
  1207.     res = objc_write_long(stream, *va_arg(args, long*));
  1208.     break;
  1209.     
  1210.       case _C_ULNG:
  1211.     res = objc_write_unsigned_long(stream, *va_arg(args, unsigned long*));
  1212.     break;
  1213.  
  1214.       case _C_CHARPTR:
  1215.     {
  1216.       char** str = va_arg(args, char**);
  1217.       res = objc_write_string (stream, *str, strlen(*str));
  1218.     }
  1219.     break;
  1220.  
  1221.       case _C_ATOM:
  1222.     {
  1223.       char** str = va_arg(args, char**);
  1224.       res = objc_write_string_atomic (stream, *str, strlen(*str));
  1225.     }
  1226.     break;
  1227.  
  1228.       case _C_ARY_B:
  1229.     {
  1230.       int len = atoi(c+1);
  1231.       const char* t = c;
  1232.       while (isdigit(*++t));
  1233.       res = objc_write_array (stream, t, len, va_arg(args, void*));
  1234.       t = objc_skip_typespec (t);
  1235.       if (*t != _C_ARY_E)
  1236.         __objc_fatal("expected `]', got: %s", t);
  1237.     }
  1238.     break; 
  1239.     
  1240.       default:
  1241.     fprintf(stderr, "objc_write_types: cannot parse typespec: %s\n", type);
  1242.     abort();
  1243.       }
  1244.     }
  1245.   va_end(args);
  1246.   return res;
  1247. }
  1248.  
  1249.  
  1250. /* 
  1251. ** Last arguments specify addresses of values to be read.  Expected
  1252. ** type is checked against the type actually present on the stream. 
  1253. */
  1254.  
  1255. int 
  1256. objc_read_types(TypedStream* stream, const char* type, ...)
  1257. {
  1258.   va_list args;
  1259.   const char *c;
  1260.   int res = 0;
  1261.  
  1262.   va_start(args, type);
  1263.  
  1264.   for (c = type; *c; c = objc_skip_typespec(c))
  1265.     {
  1266.       switch(*c) {
  1267.       case _C_ID:
  1268.     res = objc_read_object(stream, va_arg(args, id*));
  1269.     break;
  1270.  
  1271.       case _C_CLASS:
  1272.     res = objc_read_class(stream, va_arg(args, Class*));
  1273.     break;
  1274.  
  1275.       case _C_SEL:
  1276.     res = objc_read_selector(stream, va_arg(args, SEL*));
  1277.     break;
  1278.     
  1279.       case _C_CHR:
  1280.     res = objc_read_char(stream, va_arg(args, char*));
  1281.     break;
  1282.     
  1283.       case _C_UCHR:
  1284.     res = objc_read_unsigned_char(stream, va_arg(args, unsigned char*));
  1285.     break;
  1286.     
  1287.       case _C_SHT:
  1288.     res = objc_read_short(stream, va_arg(args, short*));
  1289.     break;
  1290.  
  1291.       case _C_USHT:
  1292.     res = objc_read_unsigned_short(stream, va_arg(args, unsigned short*));
  1293.     break;
  1294.  
  1295.       case _C_INT:
  1296.     res = objc_read_int(stream, va_arg(args, int*));
  1297.     break;
  1298.     
  1299.       case _C_UINT:
  1300.     res = objc_read_unsigned_int(stream, va_arg(args, unsigned int*));
  1301.     break;
  1302.  
  1303.       case _C_LNG:
  1304.     res = objc_read_long(stream, va_arg(args, long*));
  1305.     break;
  1306.     
  1307.       case _C_ULNG:
  1308.     res = objc_read_unsigned_long(stream, va_arg(args, unsigned long*));
  1309.     break;
  1310.  
  1311.       case _C_CHARPTR:
  1312.       case _C_ATOM:
  1313.     {
  1314.       char** str = va_arg(args, char**);
  1315.       res = objc_read_string (stream, str);
  1316.     }
  1317.     break;
  1318.  
  1319.       case _C_ARY_B:
  1320.     {
  1321.       int len = atoi(c+1);
  1322.       const char* t = c;
  1323.       while (isdigit(*++t));
  1324.       res = objc_read_array (stream, t, len, va_arg(args, void*));
  1325.       t = objc_skip_typespec (t);
  1326.       if (*t != _C_ARY_E)
  1327.         __objc_fatal("expected `]', got: %s", t);
  1328.     }
  1329.     break; 
  1330.     
  1331.       default:
  1332.     fprintf(stderr, "objc_read_types: cannot parse typespec: %s\n", type);
  1333.     abort();
  1334.       }
  1335.     }
  1336.   va_end(args);
  1337.   return res;
  1338. }
  1339.  
  1340. /*
  1341. ** Write an array of COUNT elements of TYPE from the memory address DATA.
  1342. ** This is equivalent of objc_write_type (stream, "[N<type>]", data)
  1343. */
  1344.  
  1345. int
  1346. objc_write_array (TypedStream* stream, const char* type,
  1347.           int count, const void* data)
  1348. {
  1349.   int off = objc_sizeof_type(type);
  1350.   const char* where = data;
  1351.  
  1352.   while (count-- > 0)
  1353.     {
  1354.       objc_write_type(stream, type, where);
  1355.       where += off;
  1356.     }
  1357.   return 1;
  1358. }
  1359.  
  1360. /*
  1361. ** Read an array of COUNT elements of TYPE into the memory address
  1362. ** DATA.  The memory pointed to by data is supposed to be allocated
  1363. ** by the callee.  This is equivalent of 
  1364. **   objc_read_type (stream, "[N<type>]", data)
  1365. */
  1366.  
  1367. int
  1368. objc_read_array (TypedStream* stream, const char* type,
  1369.          int count, void* data)
  1370. {
  1371.   int off = objc_sizeof_type(type);
  1372.   char* where = (char*)data;
  1373.  
  1374.   while (count-- > 0)
  1375.     {
  1376.       objc_read_type(stream, type, where);
  1377.       where += off;
  1378.     }
  1379.   return 1;
  1380. }
  1381.  
  1382. static void
  1383. __objc_free (void* p)
  1384. {
  1385.   free (p);
  1386. }
  1387.  
  1388. static int 
  1389. __objc_fread(FILE* file, char* data, int len)
  1390. {
  1391.   return fread(data, len, 1, file);
  1392. }
  1393.  
  1394. static int 
  1395. __objc_fwrite(FILE* file, char* data, int len)
  1396. {
  1397.   return fwrite(data, len, 1, file);
  1398. }
  1399.  
  1400. static int
  1401. __objc_feof(FILE* file)
  1402. {
  1403.   return feof(file);
  1404. }
  1405.  
  1406. static int 
  1407. __objc_no_write(FILE* file, char* data, int len)
  1408. {
  1409.   __objc_fatal ("TypedStream not open for writing");
  1410. }
  1411.  
  1412. static int 
  1413. __objc_no_read(FILE* file, char* data, int len)
  1414. {
  1415.   __objc_fatal ("TypedStream not open for reading");
  1416. }
  1417.  
  1418. static int
  1419. __objc_read_typed_stream_signature (TypedStream* stream)
  1420. {
  1421.   char buffer[80];
  1422.   int pos = 0;
  1423.   do
  1424.     (*stream->read)(stream->physical, buffer+pos, 1);
  1425.   while (buffer[pos++] != '\0');
  1426.   sscanf (buffer, "GNU TypedStream %d", &stream->version);
  1427.   if (stream->version != OBJC_TYPED_STREAM_VERSION)
  1428.     __objc_fatal ("cannot handle TypedStream version %d", stream->version);
  1429.   return 1;
  1430. }
  1431.  
  1432. static int
  1433. __objc_write_typed_stream_signature (TypedStream* stream)
  1434. {
  1435.   char buffer[80];
  1436.   sprintf(buffer, "GNU TypedStream %d", OBJC_TYPED_STREAM_VERSION);
  1437.   stream->version = OBJC_TYPED_STREAM_VERSION;
  1438.   (*stream->write)(stream->physical, buffer, strlen(buffer)+1);
  1439.   return 1;
  1440. }
  1441.  
  1442. static void __objc_finish_write_root_object(struct objc_typed_stream* stream)
  1443. {
  1444.   hash_delete (stream->object_table);
  1445.   stream->object_table = hash_new(64,
  1446.                   (hash_func_type)hash_ptr,
  1447.                   (compare_func_type)compare_ptrs);
  1448. }
  1449.  
  1450. static void __objc_finish_read_root_object(struct objc_typed_stream* stream)
  1451. {
  1452.   node_ptr node;
  1453.   struct objc_list* free_list;
  1454.   SEL awake_sel = sel_get_any_uid ("awake");
  1455.  
  1456.   /* resolve object forward references */
  1457.   free_list = list_cons(NULL, NULL);
  1458.   for (node = hash_next (stream->object_refs, NULL); node;
  1459.        node = hash_next (stream->object_refs, node))
  1460.     {
  1461.       struct objc_list* reflist = node->value;
  1462.       const void* key = node->key;
  1463.       id object = hash_value_for_key (stream->object_table, key);
  1464.       while(reflist)
  1465.     {
  1466.       *((id*)reflist->head) = object;
  1467.           if (list_find(&free_list, reflist) == NULL)
  1468.         free_list = list_cons (reflist, free_list);
  1469.       reflist = reflist->tail;
  1470.     }
  1471.     }
  1472.   list_mapcar (free_list, __objc_free);
  1473.   list_free (free_list);
  1474.  
  1475.   /* empty object reference table */
  1476.   hash_delete (stream->object_refs);
  1477.   stream->object_refs = hash_new(8, (hash_func_type)hash_ptr,
  1478.                  (compare_func_type)compare_ptrs);
  1479.   
  1480.   /* call -awake for all objects read  */
  1481.   if (awake_sel)
  1482.     {
  1483.       for (node = hash_next (stream->object_table, NULL); node;
  1484.        node = hash_next (stream->object_table, node))
  1485.     {
  1486.       id object = node->value;
  1487.       if (__objc_responds_to (object, awake_sel))
  1488.         (*objc_msg_lookup(object, awake_sel))(object, awake_sel);
  1489.     }
  1490.     }
  1491.  
  1492.   /* empty object table */
  1493.   hash_delete (stream->object_table);
  1494.   stream->object_table = hash_new(64,
  1495.                   (hash_func_type)hash_ptr,
  1496.                   (compare_func_type)compare_ptrs);
  1497. }
  1498.  
  1499. /*
  1500. ** Open the stream PHYSICAL in MODE
  1501. */
  1502.  
  1503. TypedStream* 
  1504. objc_open_typed_stream (FILE* physical, int mode)
  1505. {
  1506.   TypedStream* s = (TypedStream*)__objc_xmalloc(sizeof(TypedStream));
  1507.  
  1508.   s->mode = mode;
  1509.   s->physical = physical;
  1510.   s->stream_table = hash_new(64,
  1511.                  (hash_func_type)hash_ptr,
  1512.                  (compare_func_type)compare_ptrs);
  1513.   s->object_table = hash_new(64,
  1514.                  (hash_func_type)hash_ptr,
  1515.                  (compare_func_type)compare_ptrs);
  1516.   s->eof = (objc_typed_eof_func)__objc_feof;
  1517.   s->flush = (objc_typed_flush_func)fflush;
  1518.   s->writing_root_p = 0;
  1519.   if (mode == OBJC_READONLY)
  1520.     {
  1521.       s->class_table = hash_new(8, (hash_func_type)hash_string,
  1522.                 (compare_func_type)compare_strings);
  1523.       s->object_refs = hash_new(8, (hash_func_type)hash_ptr,
  1524.                 (compare_func_type)compare_ptrs);
  1525.       s->read = (objc_typed_read_func)__objc_fread;
  1526.       s->write = (objc_typed_write_func)__objc_no_write;
  1527.       __objc_read_typed_stream_signature (s);
  1528.     }
  1529.   else if (mode == OBJC_WRITEONLY)
  1530.     {
  1531.       s->class_table = 0;
  1532.       s->object_refs = 0;
  1533.       s->read = (objc_typed_read_func)__objc_no_read;
  1534.       s->write = (objc_typed_write_func)__objc_fwrite;
  1535.       __objc_write_typed_stream_signature (s);
  1536.     }      
  1537.   else
  1538.     {
  1539.       objc_close_typed_stream (s);
  1540.       return NULL;
  1541.     }
  1542.   s->type = OBJC_FILE_STREAM;
  1543.   return s;
  1544. }
  1545.  
  1546. /*
  1547. ** Open the file named by FILE_NAME in MODE
  1548. */
  1549.  
  1550. TypedStream*
  1551. objc_open_typed_stream_for_file (const char* file_name, int mode)
  1552. {
  1553.   FILE* file = NULL;
  1554.   TypedStream* s;
  1555.  
  1556.   if (mode == OBJC_READONLY)
  1557.     file = fopen (file_name, "r");
  1558.   else
  1559.     file = fopen (file_name, "w");
  1560.  
  1561.   if (file)
  1562.     {
  1563.       s = objc_open_typed_stream (file, mode);
  1564.       if (s)
  1565.     s->type |= OBJC_MANAGED_STREAM;
  1566.       return s;
  1567.     }
  1568.   else
  1569.     return NULL;
  1570. }
  1571.  
  1572. /*
  1573. ** Close STREAM freeing the structure it self.  If it was opened with 
  1574. ** objc_open_typed_stream_for_file, the file will also be closed.
  1575. */
  1576.  
  1577. void
  1578. objc_close_typed_stream (TypedStream* stream)
  1579. {
  1580.   if (stream->mode == OBJC_READONLY)
  1581.     {
  1582.       __objc_finish_read_root_object (stream); /* Just in case... */
  1583.       hash_delete (stream->class_table);
  1584.       hash_delete (stream->object_refs);
  1585.     }
  1586.  
  1587.   hash_delete (stream->stream_table);
  1588.   hash_delete (stream->object_table);
  1589.  
  1590.   if (stream->type == (OBJC_MANAGED_STREAM | OBJC_FILE_STREAM))
  1591.     fclose ((FILE*)stream->physical);
  1592.  
  1593.   free (stream);
  1594. }
  1595.  
  1596. BOOL
  1597. objc_end_of_typed_stream (TypedStream* stream)
  1598. {
  1599.   return (*stream->eof)(stream->physical);
  1600. }
  1601.  
  1602. void
  1603. objc_flush_typed_stream (TypedStream* stream)
  1604. {
  1605.   (*stream->flush)(stream->physical);
  1606. }
  1607.  
  1608. long
  1609. objc_get_stream_class_version (TypedStream* stream, Class class)
  1610. {
  1611.   if (stream->class_table)
  1612.     return PTR2LONG(hash_value_for_key (stream->class_table, class->name));
  1613.   else
  1614.     return class_get_version (class);
  1615. }
  1616.  
  1617.